/* eslint-disable */
var ace = require('brace')
ace.define(
  'ace/ext/beautify',
  ['require', 'exports', 'module', 'ace/token_iterator'],
  function (require, exports, module) {
    // [WIP]
    'use strict'
    var TokenIterator = require('ace/token_iterator').TokenIterator
    function is(token, type) {
      return token.type.lastIndexOf(type + '.xml') > -1
    }
    exports.singletonTags = [
      'area',
      'base',
      'br',
      'col',
      'command',
      'embed',
      'hr',
      'html',
      'img',
      'input',
      'keygen',
      'link',
      'meta',
      'param',
      'source',
      'track',
      'wbr'
    ]
    exports.blockTags = [
      'article',
      'aside',
      'blockquote',
      'body',
      'div',
      'dl',
      'fieldset',
      'footer',
      'form',
      'head',
      'header',
      'html',
      'nav',
      'ol',
      'p',
      'script',
      'section',
      'style',
      'table',
      'tbody',
      'tfoot',
      'thead',
      'ul'
    ]
    exports.formatOptions = {
      lineBreaksAfterCommasInCurlyBlock: true
    }
    exports.beautify = function (session) {
      var iterator = new TokenIterator(session, 0, 0)
      var token = iterator.getCurrentToken()
      var tabString = session.getTabString()
      var singletonTags = exports.singletonTags
      var blockTags = exports.blockTags
      var formatOptions = exports.formatOptions || {}
      var nextToken
      var breakBefore = false
      var spaceBefore = false
      var spaceAfter = false
      var code = ''
      var value = ''
      var tagName = ''
      var depth = 0
      var lastDepth = 0
      var lastIndent = 0
      var indent = 0
      var unindent = 0
      var roundDepth = 0
      var curlyDepth = 0
      var row
      var curRow = 0
      var rowsToAdd = 0
      var rowTokens = []
      var abort = false
      var i
      var indentNextLine = false
      var inTag = false
      var inCSS = false
      var inBlock = false
      var levels = { 0: 0 }
      var parents = []
      var caseBody = false
      var trimNext = function () {
        if (nextToken && nextToken.value && nextToken.type !== 'string.regexp')
          nextToken.value = nextToken.value.replace(/^\s*/, '')
      }
      var trimLine = function () {
        var end = code.length - 1
        while (true) {
          if (end == 0) break
          if (code[end] !== ' ') break
          end = end - 1
        }
        code = code.slice(0, end + 1)
      }
      var trimCode = function () {
        code = code.trimRight()
        breakBefore = false
      }
      while (token !== null) {
        curRow = iterator.getCurrentTokenRow()
        rowTokens = iterator.$rowTokens
        nextToken = iterator.stepForward()
        if (typeof token !== 'undefined') {
          value = token.value
          unindent = 0
          inCSS = tagName === 'style' || session.$modeId === 'ace/mode/css'
          if (is(token, 'tag-open')) {
            inTag = true
            if (nextToken) inBlock = blockTags.indexOf(nextToken.value) !== -1
            if (value === '</') {
              if (inBlock && !breakBefore && rowsToAdd < 1) rowsToAdd++
              if (inCSS) rowsToAdd = 1
              unindent = 1
              inBlock = false
            }
          } else if (is(token, 'tag-close')) {
            inTag = false
          } else if (is(token, 'comment.start')) {
            inBlock = true
          } else if (is(token, 'comment.end')) {
            inBlock = false
          }
          if (
            !inTag &&
            !rowsToAdd &&
            token.type === 'paren.rparen' &&
            token.value.substr(0, 1) === '}'
          ) {
            rowsToAdd++
          }
          if (curRow !== row) {
            rowsToAdd = curRow
            if (row) rowsToAdd -= row
          }
          if (rowsToAdd) {
            trimCode()
            for (; rowsToAdd > 0; rowsToAdd--) code += '\n'
            breakBefore = true
            if (!is(token, 'comment') && !token.type.match(/^(comment|string)$/))
              value = value.trimLeft()
          }
          if (value) {
            if (
              token.type === 'keyword' &&
              value.match(/^(if|else|elseif|for|foreach|while|switch)$/)
            ) {
              parents[depth] = value
              trimNext()
              spaceAfter = true
              if (value.match(/^(else|elseif)$/)) {
                if (code.match(/\}[\s]*$/)) {
                  trimCode()
                  spaceBefore = true
                }
              }
            } else if (token.type === 'paren.lparen') {
              trimNext()
              if (value.substr(-1) === '{') {
                spaceAfter = true
                indentNextLine = false
                if (!inTag) rowsToAdd = 1
              }
              if (value.substr(0, 1) === '{') {
                spaceBefore = true
                if (code.substr(-1) !== '[' && code.trimRight().substr(-1) === '[') {
                  trimCode()
                  spaceBefore = false
                } else if (code.trimRight().substr(-1) === ')') {
                  trimCode()
                } else {
                  trimLine()
                }
              }
            } else if (token.type === 'paren.rparen') {
              unindent = 1
              if (value.substr(0, 1) === '}') {
                if (parents[depth - 1] === 'case') unindent++
                if (code.trimRight().substr(-1) === '{') {
                  trimCode()
                } else {
                  spaceBefore = true
                  if (inCSS) rowsToAdd += 2
                }
              }
              if (value.substr(0, 1) === ']') {
                if (code.substr(-1) !== '}' && code.trimRight().substr(-1) === '}') {
                  spaceBefore = false
                  indent++
                  trimCode()
                }
              }
              if (value.substr(0, 1) === ')') {
                if (code.substr(-1) !== '(' && code.trimRight().substr(-1) === '(') {
                  spaceBefore = false
                  indent++
                  trimCode()
                }
              }
              trimLine()
            } else if (
              (token.type === 'keyword.operator' || token.type === 'keyword') &&
              value.match(/^(=|==|===|!=|!==|&&|\|\||and|or|xor|\+=|.=|>|>=|<|<=|=>)$/)
            ) {
              trimCode()
              trimNext()
              spaceBefore = true
              spaceAfter = true
            } else if (token.type === 'punctuation.operator' && value === ';') {
              trimCode()
              trimNext()
              spaceAfter = true
              if (inCSS) rowsToAdd++
            } else if (token.type === 'punctuation.operator' && value.match(/^(:|,)$/)) {
              trimCode()
              trimNext()
              if (
                value.match(/^(,)$/) &&
                curlyDepth > 0 &&
                roundDepth === 0 &&
                formatOptions.lineBreaksAfterCommasInCurlyBlock
              ) {
                rowsToAdd++
              } else {
                spaceAfter = true
                breakBefore = false
              }
            } else if (token.type === 'support.php_tag' && value === '?>' && !breakBefore) {
              trimCode()
              spaceBefore = true
            } else if (is(token, 'attribute-name') && code.substr(-1).match(/^\s$/)) {
              spaceBefore = true
            } else if (is(token, 'attribute-equals')) {
              trimLine()
              trimNext()
            } else if (is(token, 'tag-close')) {
              trimLine()
              if (value === '/>') spaceBefore = true
            } else if (token.type === 'keyword' && value.match(/^(case|default)$/)) {
              if (caseBody) unindent = 1
            }
            if (
              breakBefore &&
              !(token.type.match(/^(comment)$/) && !value.substr(0, 1).match(/^[/#]$/)) &&
              !(token.type.match(/^(string)$/) && !value.substr(0, 1).match(/^['"@]$/))
            ) {
              indent = lastIndent
              if (depth > lastDepth) {
                indent++
                for (i = depth; i > lastDepth; i--) levels[i] = indent
              } else if (depth < lastDepth) indent = levels[depth]
              lastDepth = depth
              lastIndent = indent
              if (unindent) indent -= unindent
              if (indentNextLine && !roundDepth) {
                indent++
                indentNextLine = false
              }
              for (i = 0; i < indent; i++) code += tabString
            }
            if (token.type === 'keyword' && value.match(/^(case|default)$/)) {
              if (caseBody === false) {
                parents[depth] = value
                depth++
                caseBody = true
              }
            } else if (token.type === 'keyword' && value.match(/^(break)$/)) {
              if (parents[depth - 1] && parents[depth - 1].match(/^(case|default)$/)) {
                depth--
                caseBody = false
              }
            }
            if (token.type === 'paren.lparen') {
              roundDepth += (value.match(/\(/g) || []).length
              curlyDepth += (value.match(/\{/g) || []).length
              depth += value.length
            }
            if (token.type === 'keyword' && value.match(/^(if|else|elseif|for|while)$/)) {
              indentNextLine = true
              roundDepth = 0
            } else if (!roundDepth && value.trim() && token.type !== 'comment')
              indentNextLine = false
            if (token.type === 'paren.rparen') {
              roundDepth -= (value.match(/\)/g) || []).length
              curlyDepth -= (value.match(/\}/g) || []).length
              for (i = 0; i < value.length; i++) {
                depth--
                if (value.substr(i, 1) === '}' && parents[depth] === 'case') {
                  depth--
                }
              }
            }
            if (token.type == 'text') value = value.replace(/\s+$/, ' ')
            if (spaceBefore && !breakBefore) {
              trimLine()
              if (code.substr(-1) !== '\n') code += ' '
            }
            code += value
            if (spaceAfter) code += ' '
            breakBefore = false
            spaceBefore = false
            spaceAfter = false
            if (
              (is(token, 'tag-close') && (inBlock || blockTags.indexOf(tagName) !== -1)) ||
              (is(token, 'doctype') && value === '>')
            ) {
              if (inBlock && nextToken && nextToken.value === '</') rowsToAdd = -1
              else rowsToAdd = 1
            }
            if (nextToken && singletonTags.indexOf(nextToken.value) === -1) {
              if (is(token, 'tag-open') && value === '</') {
                depth--
              } else if (is(token, 'tag-open') && value === '<') {
                depth++
              } else if (is(token, 'tag-close') && value === '/>') {
                depth--
              }
            }
            if (is(token, 'tag-name')) {
              tagName = value
            }
            row = curRow
          }
        }
        token = nextToken
      }
      code = code.trim()
      session.doc.setValue(code)
    }
  }
)
ace.acequire(['ace/ext/beautify'], function () {})
